//
//  ServerProxy.m
//  e-nurse
//
//  Created by  on 9/26/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "ServerProxy.h"
#import "User.h"
#import "TaskWorker.h"
#import "URLConnection.h"
#import "JSONSerializer.h"
#import "LoginResult.h"
#import "RegisterResult.h"
#import "Database.h"
#import "ForgetPasswordResult.h"
#import "ActivateCode.h"
#import "ActivateResult.h"
#import "XAuthObject.h"
#import "ResendActivateCodeResult.h"
#import "Record.h"

#define STATUS_CACHE_ONLINE "STATUS_CACHE_ONLINE"
#define STATUS_CACHE_ONLINE_USER "STATUS_CACHE_ONLINE_USER"
#define STATUS_CACHE_ONLINE_USER_ACTIVATED "STATUS_CACHE_ONLINE_USER_ACTIVATED"

#define SERVER "http://enurse.sinaapp.com/api/"
#define API_VERSION "v1/"
#define API_SIGN_IN "pass/signin/"
#define API_SIGN_OUT "users/signout/"
#define API_REGISTER "pass/reg/"
#define API_GET_USER "users/%d/"
#define API_FORGET_PASSWORD "pass/getpwd/"
#define API_ACTIVATE_USER "users/activate/"
#define API_RESEND_ACTIVATE_CODE "users/resend/"
#define API_FEEDBACK "fdbk/"
#define API_ADD_RECORD "bpi/"

static ServerProxy* sharedInstance = nil;

@interface ServerProxy (){
@private
    BOOL _isOnline;
    BOOL _isFeedbackSuccess;
}

@property (strong, nonatomic) TaskWorker *taskWorker;
@property (assign, nonatomic) SEL loginCompletedAction;
@property (strong, nonatomic) id loginCompletedActionTarget;
@property (assign, nonatomic) SEL registerCompletedAction;
@property (strong, nonatomic) id registerCompletedActionTarget;
@property (assign, nonatomic) SEL forgetPasswordCompletedAction;
@property (strong, nonatomic) id forgetPasswordCompletedActionTarget;
@property (assign, nonatomic) SEL activateCompletedAction;
@property (strong, nonatomic) id activateCompletedActionTarget;
@property (assign, nonatomic) SEL feedbackCompletedAction;
@property (strong, nonatomic) id feedbackCompletedActionTarget;
@property (assign, nonatomic) SEL addRecordCompletedAction;
@property (strong, nonatomic) id addRecordCompletedActionTarget;
@property (strong, nonatomic) ForgetPasswordResult* forgetPassResult;
@property (strong, nonatomic) RegisterResult* registerResult;
@property (strong, nonatomic) ActivateResult* activateResult;
@property (strong, nonatomic) LoginResult* loginResult;
@property (strong, nonatomic) ResendActivateCodeResult* resendActivateCodeResult;
@property (strong, nonatomic) NSString* apiKey;

- (void)initOnlineStatus;
- (void)serializeOnlineStatus;

- (void)processLogin:(User*)user;
- (void)processLoginCompleted:(User*)user;

- (void)processRegister:(User*)user;
- (void)processRegisterCompleted:(User*)user;

- (void)processForgetPassword:(User*)user;
- (void)processForgetPasswordCompleted:(User*)user;

- (void)processActivate:(ActivateCode*)code;
- (void)processActivateCompleted:(ActivateCode*)code;

- (void)processResendActivateCode:(XAuthObject*)xAuthObj;
- (void)processResendActivateCodeCompleted:(XAuthObject*)xAuthObj;

- (void)processFeedback:(NSString*)content;
- (void)processFeedbackCompleted:(NSString*)content;

- (void)processAddRecord:(Record *)record;
- (void)processAddRecordCompleted:(Record *)record;

- (User*)getUserInfo:(int)userId userName:(NSString*)name apiKey:(NSString*)apiKey;
- (void)updateUserInfo:(int)userId userName:(NSString*)name apiKey:(NSString*)apiKey;
- (void)addOrUpdateCurrentUserToDatabase;

- (NSString*)getAPIUrl:(NSString*)api;

- (NSString*)buildParameters:(NSString*)firstParam, ... NS_REQUIRES_NIL_TERMINATION;

- (NSString*)buildUrl:(NSString*)url userName:(NSString*)name apiKey:(NSString*)apiKey;

@end

@implementation ServerProxy
@synthesize taskWorker = _taskWorker;
@synthesize loginCompletedAction = _loginCompletedAction;
@synthesize loginCompletedActionTarget = _loginCompletedActionTarget;
@synthesize registerCompletedAction = _registerCompletedAction;
@synthesize registerCompletedActionTarget = _registerCompletedActionTarget;
@synthesize forgetPasswordCompletedAction = _forgetPasswordCompletedAction;
@synthesize forgetPasswordCompletedActionTarget = _forgetPasswordCompletedActionTarget;
@synthesize activateCompletedAction = _activateCompletedAction;
@synthesize activateCompletedActionTarget = _activateCompletedActionTarget;
@synthesize feedbackCompletedAction =_feedbackCompletedAction;
@synthesize feedbackCompletedActionTarget = _feedbackCompletedActionTarget;
@synthesize addRecordCompletedAction = _addRecordCompletedAction;
@synthesize addRecordCompletedActionTarget = _addRecordCompletedActionTarget;
@synthesize currentUser = _currentUser;
@synthesize forgetPassResult = _forgetPassResult;
@synthesize registerResult = _registerResult;
@synthesize activateResult = _activateResult;
@synthesize loginResult = _loginResult;
@synthesize resendActivateCodeResult = _resendActivateCodeResult;
@synthesize apiKey = _apiKey;

+ (ServerProxy *)sharedInstance
{
    if (nil != sharedInstance) {
        return sharedInstance;
    }
    
    static dispatch_once_t pred;
    dispatch_once(&pred, ^{
        sharedInstance = [[ServerProxy alloc] init];
    });
    
    return sharedInstance;
}

- (id)init
{
    self = [super init];
    if(self)
    {
        self.taskWorker = [[[TaskWorker alloc] init] autorelease];
        [self initOnlineStatus];
    }
    
    return self;
}

- (void)dealloc
{
    self.taskWorker = nil;
    self.loginCompletedActionTarget = nil;
    self.registerCompletedActionTarget = nil;
    self.forgetPasswordCompletedActionTarget = nil;
    self.activateCompletedActionTarget = nil;
    self.feedbackCompletedActionTarget = nil;
    self.addRecordCompletedActionTarget = nil;
    self.currentUser = nil;
    self.forgetPassResult = nil;
    self.registerResult = nil;
    self.activateResult = nil;
    self.loginResult = nil;
    self.resendActivateCodeResult = nil;
    self.apiKey = nil;
    [super dealloc];
}

- (void)initOnlineStatus
{
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@STATUS_CACHE_ONLINE] == nil)
    {
        [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@STATUS_CACHE_ONLINE];
        _isOnline = NO;
    }
    else
    {
        _isOnline = [[[NSUserDefaults standardUserDefaults] objectForKey:@STATUS_CACHE_ONLINE] boolValue];
        self.currentUser = [[Database sharedInstance] getUserById:[[[NSUserDefaults standardUserDefaults] objectForKey:@STATUS_CACHE_ONLINE_USER] intValue]];
        self.currentUser.isActivated = [[[NSUserDefaults standardUserDefaults] objectForKey:@STATUS_CACHE_ONLINE_USER_ACTIVATED] boolValue];
    }
    
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)serializeOnlineStatus
{
    [[NSUserDefaults standardUserDefaults] setObject:(_isOnline ? @"YES" : @"NO") forKey:@STATUS_CACHE_ONLINE];
    [[NSUserDefaults standardUserDefaults] setObject:(_isOnline ? [NSString stringWithFormat:@"%d", self.currentUser.userId] : @"") forKey:@STATUS_CACHE_ONLINE_USER];
    [[NSUserDefaults standardUserDefaults] setObject:((_isOnline && self.currentUser.isActivated) ? @"YES" : @"NO") forKey:@STATUS_CACHE_ONLINE_USER_ACTIVATED];
}

- (NSString *)getApiKey
{
    return self.apiKey;
}

- (void)login:(User *)user completedAction:(SEL)aSelector target:(id)target
{
    self.loginCompletedActionTarget = target;
    self.loginCompletedAction = aSelector;
  
    [self.taskWorker processWithObject:user action:@selector(processLogin:) completedAction:@selector(processLoginCompleted:) target:self];
}

- (int)currentUserId
{
    int userId = ANONY_USER_ID;
    if([[ServerProxy sharedInstance] currentUser] != nil)
    {
        userId = [[[ServerProxy sharedInstance] currentUser] userId];
    }
    
    return userId;
}

- (NSString *)getAPIUrl:(NSString *)api
{
    return [NSString stringWithFormat:@"%@%@%@", @SERVER, @API_VERSION, api];
}

- (void)processLogin:(User*)user
{
    NSString* result = [URLConnection postRequestSync:[self getAPIUrl:@API_SIGN_IN] 
                                                        parameters:nil 
                                                        headers:nil 
                                                        body:[[self buildParameters:@"username", user.name, @"password", user.password, nil] dataUsingEncoding:NSUTF8StringEncoding]];
    
    self.apiKey = nil;
    self.currentUser = nil;
    if(![result isEqualToString:@""])
    {
        self.loginResult = [JSONSerializer deserializeLoginResult:result];
        _isOnline = self.loginResult.isOnline;
        if(self.loginResult.isOnline || (!self.loginResult.isInvalid && !self.loginResult.isActivated))
        {
            [self updateUserInfo:self.loginResult.userId userName:user.name apiKey:self.loginResult.apiKey];
            self.currentUser.isActivated = self.loginResult.isActivated;
        }
        else 
        {
            [self serializeOnlineStatus];           
        }
    }
}

- (void)processLoginCompleted:(User*)user
{
    [self.loginCompletedActionTarget performSelector:self.loginCompletedAction withObject:self.loginResult];
    self.loginResult = nil;
}

- (void)register:(User *)user completedAction:(SEL)aSelector target:(id)target
{
    self.registerCompletedActionTarget = target;
    self.registerCompletedAction = aSelector;

    [self.taskWorker processWithObject:user action:@selector(processRegister:) completedAction:@selector(processRegisterCompleted:) target:self];
}

- (void)processRegister:(User*)user
{
    NSString* result = [URLConnection postRequestSync:[self getAPIUrl:@API_REGISTER] 
                                                        parameters:nil 
                                                        headers:nil 
                                                        body:[[self buildParameters:@"username", user.name, @"password", user.password, @"telephone", user.phone, nil] dataUsingEncoding:NSUTF8StringEncoding]];
    self.registerResult = nil;
    self.apiKey = nil;
    
    if(![result isEqualToString:@""])
    {
        self.registerResult = [JSONSerializer deserializeRegisterResult:result];
        self.registerResult.userName = user.name;
        
        self.apiKey = self.registerResult.apiKey;
    }   
}

- (void)processRegisterCompleted:(User*)user
{
    [self.registerCompletedActionTarget performSelector:self.registerCompletedAction withObject:self.registerResult];
    self.registerResult = nil;
}

- (void)addOrUpdateCurrentUserToDatabase
{
    if([[Database sharedInstance] getUserById:self.currentUser.userId] == nil)
    {
        [[Database sharedInstance] addUser:self.currentUser];
    }   
    else 
    {
        [[Database sharedInstance] updateUser:self.currentUser];           
    }    
}

- (void)updateUserInfo:(int)userId userName:(NSString *)name apiKey:(NSString *)apiKey
{
    self.apiKey = apiKey;

    User* user = [self getUserInfo:userId userName:name apiKey:apiKey];
    
    if(user != nil)
    {
        self.currentUser = user;
    }
    else
    {
        user = [[User alloc] init];
        user.userId = userId;
        user.name = name;
        
        self.currentUser = user;
        
        [user release];
    }
    
    [self serializeOnlineStatus];
    [self addOrUpdateCurrentUserToDatabase];
}

-(User*)getUserInfo:(int)userId userName:(NSString*)name apiKey:(NSString*)apiKey
{
    NSString* url = [self buildUrl:[NSString stringWithFormat:[self getAPIUrl:@API_GET_USER], userId] userName:name apiKey:apiKey];
    NSString* result = [URLConnection getRequestSync:url headers:nil];
    if(![result isEqualToString:@""])
    {
        return [JSONSerializer deserializeUser:result];
    }
    else
    {
        return nil;
    }
}

- (bool)isOnline
{
    return _isOnline;
}

- (void)logout
{
//    NSString* url = [self buildUrl:[self getAPIUrl:@API_SIGN_OUT] userName:self.currentUser.name apiKey:[self apiKey]];
//   [URLConnection postRequestSync:[self getAPIUrl:url] 
//                                           parameters:nil 
//                                              headers:nil 
//                                                 body:[[self buildParameters:@"user_id", [NSString stringWithFormat:@"%d", self.currentUser.userId],nil] dataUsingEncoding:NSUTF8StringEncoding]];

    self.currentUser = nil;
    _isOnline = NO;
    [self serializeOnlineStatus];
}

- (void)forgetPassword:(User*)user completedAction:(SEL)aSelector target:(id)target
{
    self.forgetPasswordCompletedAction = aSelector;
    self.forgetPasswordCompletedActionTarget = target;

    [self.taskWorker processWithObject:user action:@selector(processForgetPassword:) completedAction:@selector(processForgetPasswordCompleted:) target:self];
}

- (void)processForgetPassword:(User*)user
{
    NSString* result = [URLConnection postRequestSync:[self getAPIUrl:@API_FORGET_PASSWORD] 
                                           parameters:nil 
                                              headers:nil 
                                                 body:[[self buildParameters:@"username", user.name, nil] dataUsingEncoding:NSUTF8StringEncoding]];
    
    self.forgetPassResult = nil;
    if(![result isEqualToString:@""])
    {
        self.forgetPassResult = [JSONSerializer deserializeForgetPasswordResult:result];
    }   
}

- (void)processForgetPasswordCompleted:(User*)user
{
    [self.forgetPasswordCompletedActionTarget performSelector:self.forgetPasswordCompletedAction withObject:self.forgetPassResult];
    self.forgetPassResult = nil;
}

- (void)activate:(int)userId activateCode:(int)code userName:(NSString*)name apiKey:(NSString*)apiKey completedAction:(SEL)aSelector target:(id)target
{
    self.activateCompletedAction = aSelector;
    self.activateCompletedActionTarget = target;
    
    ActivateCode* activateCode = [[[ActivateCode alloc] init] autorelease];
    activateCode.code = code;
    XAuthObject* xAuthObj = [[XAuthObject alloc] init];
    xAuthObj.userId = userId;
    xAuthObj.userName = name;
    xAuthObj.apiKey = apiKey;
    activateCode.xAuthObj = xAuthObj;
    
    [self.taskWorker processWithObject:activateCode action:@selector(processActivate:) completedAction:@selector(processActivateCompleted:) target:self];
}

- (void)processActivate:(ActivateCode*)code
{
    NSString* url = [self buildUrl:[self getAPIUrl:@API_ACTIVATE_USER] userName:code.xAuthObj.userName apiKey:code.xAuthObj.apiKey];
    NSString* result = [URLConnection postRequestSync:url
                                           parameters:nil 
                                              headers:nil 
                                                 body:[[self buildParameters:@"activation_code", [NSString stringWithFormat:@"%d", code.code], @"user_id", [NSString stringWithFormat:@"%d", code.xAuthObj.userId], nil] dataUsingEncoding:NSUTF8StringEncoding]];
    self.activateResult = nil;
    
    if(![result isEqualToString:@""])
    {
        self.activateResult = [JSONSerializer deserializeActivateResult:result];
        if(![self.activateResult errorCode])
        {
            _isOnline = true;
            [self updateUserInfo:code.xAuthObj.userId userName:code.xAuthObj.userName apiKey:code.xAuthObj.apiKey];
        }
    }     
}

- (void)processActivateCompleted:(ActivateCode*)code
{
    [self.activateCompletedActionTarget performSelector:self.activateCompletedAction withObject:self.activateResult];
    self.activateResult = nil;
}

- (void)resentActivateCode:(int)userId userName:(NSString*)name apiKey:(NSString*)apiKey completedAction:(SEL)aSelector target:(id)target
{
    self.activateCompletedAction = aSelector;
    self.activateCompletedActionTarget = target;
    
    XAuthObject* xAuthObj = [[[XAuthObject alloc] init] autorelease];
    xAuthObj.userId = userId;
    xAuthObj.userName = name;
    xAuthObj.apiKey = apiKey;
    [self.taskWorker processWithObject:xAuthObj action:@selector(processResendActivateCode:) completedAction:@selector(processResendActivateCodeCompleted:) target:self];
}

- (void)processResendActivateCode:(XAuthObject*)xAuthObj
{
    NSString* url = [self buildUrl:[self getAPIUrl:@API_RESEND_ACTIVATE_CODE] userName:xAuthObj.userName apiKey:xAuthObj.apiKey];
    NSString* result = [URLConnection postRequestSync:url
                                           parameters:nil 
                                              headers:nil 
                                                 body:[[self buildParameters:@"user_id", [NSString stringWithFormat:@"%d", xAuthObj.userId], nil] dataUsingEncoding:NSUTF8StringEncoding]];
    self.resendActivateCodeResult = nil;
    
    if(![result isEqualToString:@""])
    {
        self.resendActivateCodeResult = [JSONSerializer deserializeResendActivateCodeResult:result];
    }
    else
    {
        ResendActivateCodeResult* resendActivateCodeResult = [[ResendActivateCodeResult alloc] init];
        resendActivateCodeResult.errorCode = -1;
        self.resendActivateCodeResult = resendActivateCodeResult;
        
        [resendActivateCodeResult release];
    }
}

- (void)processResendActivateCodeCompleted:(XAuthObject*)xAuthObj
{
    [self.activateCompletedActionTarget performSelector:self.activateCompletedAction withObject:self.resendActivateCodeResult];
    self.resendActivateCodeResult = nil;
    self.activateCompletedActionTarget = nil;
}

-(void)feedback:(NSString *)content completedAction:(SEL)aSelector target:(id)target
{
    self.feedbackCompletedAction = aSelector;
    self.feedbackCompletedActionTarget = target;
    
    [self.taskWorker processWithObject:content action:@selector(processFeedback:) completedAction:@selector(processFeedbackCompleted:) target:self];   
}

- (void)processFeedback:(NSString*)content
{
    NSString* resourceUri = @"/api/v1/users/%d/";
    NSString* url = nil;
    if(self.currentUser != nil)
    {
        resourceUri = [NSString stringWithFormat:resourceUri, self.currentUser.userId];
        url = [self buildUrl:[self getAPIUrl:@API_FEEDBACK] userName:self.currentUser.name apiKey:[self apiKey]];
    }
    else
    {
        resourceUri = [NSString stringWithFormat:resourceUri, -1];
        url = [self buildUrl:[self getAPIUrl:@API_FEEDBACK] userName:@"Anonymous" apiKey:@"7ee16b12b9462335d65595bff0b569ffb7c88491"];
    }
    
    NSMutableDictionary* headers = [[[NSMutableDictionary alloc] init] autorelease];
    [headers setObject:@"Content-Type" forKey:@"application/json"];
    NSString* data = @"{\"app_version\":\"1.0 Beta\",\"feedback_content\":\"Test from iPhoe\",\"user\":\"/api/v1/users/-1/\",\"user_agent\":\"iPHone\"}";
    NSString* result = [URLConnection postRequestSync:[self getAPIUrl:@API_FEEDBACK]
                                           parameters:nil 
                                              headers:headers
//                                                 body:[[self buildParameters:@"app_version", @"1.0 Beta", @"user_agent", @"iPhone", @"feedback_content", content, @"user", resourceUri, nil] dataUsingEncoding:NSUTF8StringEncoding]];
//                                                 body:[[JSONSerializer serializeFeedback:content version:@"1.0 Beta" agent:@"iPHone" userUri:resourceUri] dataUsingEncoding:NSUTF8StringEncoding]];
                                                 body:[data dataUsingEncoding:NSUTF8StringEncoding]];

    _isFeedbackSuccess = ![result isEqualToString:@""];
}

- (void)processFeedbackCompleted:(NSString*)content
{
    [self.feedbackCompletedActionTarget performSelector:self.feedbackCompletedAction withObject:[NSNumber numberWithBool:_isFeedbackSuccess]];
    self.feedbackCompletedActionTarget = nil;
}

- (void)addRecord:(Record *)record completedAction:(SEL)aSelector target:(id)target
{
    self.addRecordCompletedAction = aSelector;
    self.addRecordCompletedActionTarget = target;
    
    [self.taskWorker processWithObject:record action:@selector(processAddRecord:) completedAction:@selector(processAddRecordCompleted:) target:self];
   
}

- (void)processAddRecord:(Record *)record
{
    
}

- (void)processAddRecordCompleted:(Record *)record
{
    
}

- (NSString*)buildUrl:(NSString*)url userName:(NSString*)name apiKey:(NSString*)apiKey
{
     return [NSString stringWithFormat:@"%@?%@", url, [self buildParameters:@"xauth", [NSString stringWithFormat:@"%@:%@", name, apiKey], nil]];   
}

-(NSString*)buildParameters:(NSString *)firstParam, ...
{
    va_list args;
    va_start(args, firstParam);
    
    NSMutableString* result = [[[NSMutableString alloc] init] autorelease];
    
    [result appendFormat:@"%@", firstParam];
    BOOL isSettingKey = NO;
    
    for(NSString *str = va_arg(args, NSString*); str != nil; str = va_arg(args, NSString*))
    {
        if(!isSettingKey)
        {
            [result appendFormat:@"=%@", str];
        }
        else
        {
            [result appendFormat:@"&%@", str];
        }
        
        isSettingKey = !isSettingKey;
    }
    
    va_end(args);
    
    return result;
}

@end
